---
id: overview
title: Interactions Overview
hide_title: true
---

# Moti Interactions

<img
  src="/img/Interactions.png"
  style={{ borderRadius: 16, display: 'block' }}
/>

## Snippet

```jsx
<MotiPressable
  onPress={onPress}
  animate={({ hovered, pressed }) => {
    'worklet'

    return {
      opacity: hovered || pressed ? 0.5 : 1,
    }
  }}
/>
```

## Video

<div
  style={{
    position: 'relative',
    paddingBottom: '56.25%',
    height: 0,
    width: '100%',
  }}
>
  <iframe
    src="https://www.loom.com/embed/df83293c3af64cefbc45e61d945ec772"
    frameborder="0"
    webkitallowfullscreen
    mozallowfullscreen
    allowfullscreen
    style={{
      position: 'absolute',
      top: 0,
      left: 0,
      right: 0,
      bottom: 0,
      width: '100%',
      height: '100%',
    }}
  ></iframe>
</div>

<br />

First, import:

```tsx
import { MotiPressable } from 'moti/interactions'
```

Next, animate your interactions:

```tsx
const onPress = () => Linking.openURL('beatgig.com')

<MotiPressable
  onPress={onPress}
  animate={({ hovered, pressed }) => {
    'worklet'

    return {
      opacity: hovered || pressed ? 0.5 : 1,
    }
  }}
/>
```

## About

The `MotiPressable` component lets you animate based on `pressed` and `hovered` interactions, without triggering any re-renders.

The usage is very similar to `Pressable` from `react-native`.

The two differences are 1) you use the `animate` prop rather than `style`, and 2) the function you pass must be a `worklet`, resulting in faster performance and a better developer experience.

Like always, `MotiPressable` relies on the native thread when tracking interactions.

### Examples

Check out these tweets from [Fernando Rojo](https://twitter.com/fernandotherojo) for more context:

- [From Moti's API to MotiPressable](https://twitter.com/FernandoTheRojo/status/1431421726748024836)
- [Remaking BeatGig's web dropdown menu with moti interactions](https://twitter.com/FernandoTheRojo/status/1432113422368448516?s=20)
- [Animating children of a Pressable component without re-renders](https://twitter.com/FernandoTheRojo/status/1431768719886323714?s=20)

<!--
### Examples

There are some examples in the `examples/sample/src` folder of the Moti repo.
-->

## Installation

Versions before 0.17.0 required you to install `@motify/interactions`. This is no longer the case. [See the PR](https://github.com/nandorojo/moti/pull/136).

Interactions now comes bundled with `moti`. You can import it like so:

```tsx
import { MotiPressable } from 'moti/interactions'
```

### Peer dependencies

As of `moti@0.17.0`, `moti/interactions` uses `react-native-gesture-handler` v2. Upgrading may not be required, but it is recommended. This is the version included in Expo SDK 44.

You'll need to wrap your app with `GestureHandlerRootView` from `react-native-gesture-handler`. Please [see their docs](https://docs.swmansion.com/react-native-gesture-handler/docs/#js) for installation instructions.

## Animating children

A common use-case of a component like `Pressable` is styling children based on the animation state.

Before `moti`, you might do this with the React Native `Pressable` component.

```tsx
<Pressable>
  {({ pressed }) => <View style={{ opacity: pressed ? 0.5 : 1 }} />}
</Pressable>
```

Moti takes a different approach to improve performance and composition.

Rather than using React state to track the interaction, Moti uses Reanimated shared values with React Native Gesture Handler.

As a result, Moti's interactions trigger zero re-renders, and all animations are handled on the native thread.

### The Moti way

Let's see what the above example might look like with Moti.

First, change `Pressable` to `MotiPressable`. Next, remove the function child, and instead pass a component directly. Let's call it `Child`.

```tsx
<MotiPressable>
  <Child />
<MotiPressable>
```

Then, in the `Child` component, we can access the parent's interaction state with `useMotiPressable`

```tsx
import { useMotiPressable } from moti/interactions'

const Child = () => {
  const state = useMotiPressable(({ pressed }) => {
    'worklet'

    return {
      opacity: pressed ? 0.5 : 1,
    }
  }, [])
  return <MotiView state={state} />
}
```

### Access a specific parent

`useMotiPressable` also optionally takes a unique `id` as its first argument. This lets you access a specific parent pressable's interaction.

For example, say you have a `list` component at the root, and you want to access its state:

```tsx
<MotiPressable id="list">
  {items.map(id =>
    <MotiPressable key={id}>
      <Child />
    </MotiPressable>
  )}
<MotiPressable>
```

Notice that the `MotiPressable` component now has an `id="list"` prop. This tells all of its children that it can be uniquely referred to as `list`.

By default, the `useMotiPressable` would access the interaction state of its closest `MotiPressable` parent. That default behavior doesn't work for this case, since we want to animate based on the top-level list component.

In the `Child` component, pass `list` as the first argument to `useMotiPressable`.

```tsx
import { useMotiPressable } from moti/interactions'

const Child = () => {
  const state = useMotiPressable(
    'list',
    ({ pressed }) => {
      'worklet'

      return {
        opacity: pressed ? 0.5 : 1,
      }
    },
    []
  )
  return <MotiView state={state} />
}
```

That's it. Now, `useMotiPressable` will return animate based on the interaction state of the outer-most `MotiPressable`.

### Access multiple parents

In the previous section, we saw how to access a unique parent's interaction state. But what if we want to _combine_ the interaction states of multiple components for more complex animations?

That's easy too. Our previous example looked like this:

```tsx
<MotiPressable id="list">
  {items.map(id =>
    <MotiPressable key={id}>
      <Child />
    </MotiPressable>
  )}
<MotiPressable>
```

Let's add a unique `id` prop to each `MotiPressable` item that's rendered in the list, called `item-${id}`.

Let's also pass the `id` as a prop to the `Child`.

```tsx
<MotiPressable id="list">
  {items.map(id =>
    <MotiPressable id={`item-${id}`} key={id}>
      <Child id={id} />
    </MotiPressable>
  )}
<MotiPressable>
```

Now, the `Child` component can call `useMotiPressables` instead of `useMotiPressable`.

Say we want to make all items fade away when you hover over the list, _except_ for the actual item you're hovering.

```tsx
import { useMotiPressables } from moti/interactions'

const Child = ({ id }) => {
  const state = useMotiPressables((containers) => {
    'worklet'

    // access items by their unique IDs
    const list = containers.list.value
    const item = containers[`item-${id}`].value

    let opacity = 1

    if (list.hovered && !item.hovered) {
      opacity = 0.5
    }

    return {
      opacity,
    }
  }, [])
  return <MotiView state={state} />
}
```

### Animated props

Let's say you want to update a child component's props based on a parent's interaction state.

For example, you have a dropdown menu whose `pointerEvents` should be `none` when its container isn't hovered.

```tsx
const Menu = () => {
  return (
    <MotiPressable id="menu">
      <MenuItems />
    </MotiPressable>
  )
}

const MenuItems = () => {
  const animatedProps = useMotiPressableAnimatedProps(
    'menu', // optional, access a unique pressable parent
    ({ hovered }) => {
      'worklet'

      return {
        pointerEvents: hovered ? 'auto' : 'none',
      }
    },
    []
  )
  return (
    <MotiView animatedProps={animatedProps}>{/* Menu items here...*/}</MotiView>
  )
}
```

You can also pass a TypeScript generic to `useMotiPressableAnimatedProps`:

```tsx
import { ViewProps } from 'react-native'

// in your component:
const animatedProps = useMotiPressableAnimatedProps<ViewProps>(
  'menu',
  ({ hovered }) => {
    'worklet'

    return {
      pointerEvents: hovered ? 'auto' : 'none',
    }
  },
  []
)
```

`useMotiPressableAnimatedProps` relies on `useAnimatedProps` under the hood.

> `animatedProps` cannot be used with `animate` on the same prop on Web. If you need to do both, please split your usage into two components; one that receives the `animate` prop, and another that receives `animateProps`. This is a reanimated limitation.

### Interpolate interaction state

A rare but available use-case is `useInterpolateMotiPressable`.

As the name implies, this lets you access the shared value state of a parent pressable.

Example:

```tsx
import { useSharedValue } from 'react-native-reanimated'
import { useInterpolateMotiPressable } from moti/interactions'

// in your component
const mySharedValue = useSharedValue(0)
useInterpolateMotiPressable(({ pressed }) => {
  'worklet'

  mySharedValue.value = pressed ? 1 : 0
})
```

If you're passing a unique `id` prop to your pressable, you can also isolate this hook to that pressable.

Say the parent pressable has `id="list"`, and you want to isolate this hook to the `list` pressable:

```tsx
<MotiPressable id="menu">
  <Item />
</MotiPressable>
```

Then, in the `Item` component:

```tsx
const mySharedValue = useSharedValue(0)
useInterpolateMotiPressable('list', ({ pressed }) => {
  'worklet'

  mySharedValue.value = pressed ? 1 : 0
})
```

It returns an `Animated.DerivedValue`. You can also type it with a generic:

```tsx
const swipePosition = useSharedValue(0)
const interpolatedValue = useInterpolateMotiPressable<{ done: boolean }>(
  'list',
  ({ pressed }) => {
    'worklet'

    return {
      done: swipePosition.value > 50 && !pressed,
    }
  }
)
```

Just like any derived value, you can read the value it returns with `.value`:

```tsx
const swipePosition = useSharedValue(0)
const interpolatedValue = useInterpolateMotiPressable<{ done: boolean }>(
  'list',
  ({ pressed }) => {
    'worklet'

    return {
      done: swipePosition.value > 50 && !pressed,
    }
  }
)

// then, in some worklet
const done = state.value.done
```

## Performance

By default, this component should have better performance than the native `Pressable`. It triggers zero re-renders, and all animations are run on the native thread.

If your component re-renders often, consider wrapping your hook with `useCallback` to improve performance:

```tsx
const animate = useCallback<MotiPressableInteractionProp>(({ pressed }) => {
  'worklet'

  return {
    opacity: hovered || pressed ? 0.5 : 1,
  }
}, [])

<MotiPressable
  animate={animate}
/>
```

For all the hooks provided, you can also pass a dependency array to improve performance. It works just like the dependency array for `useMemo`, and it's always the last argument for any of the pressable hooks.

```tsx
const state = useMotiPressable(({ pressed }) => {
  'worklet'

  return {
    opacity: pressed ? 0.5 : 1,
  }
}, []) // see this array here!

return <MotiView state={state} />
```

## Web Support

`MotiPressable` provides first-class support for Web, including `hovered` and `pressed` interactions.

Please note that Reanimated 3 uses JS animations on Web. That said, `MotiPressable` still doesn't trigger re-renders on web.
